package org.springblade.core.tool.utils;

import cn.hutool.core.util.ObjectUtil;

import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collector;

/**
 * 工具类
 */
public class FnKit {

    /**
     * 过滤出符合条件对象
     *
     * @param dataList
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> List<T> filter(Collection<T> dataList, Predicate<T> predicate) {
        if (dataList == null || dataList.size() == 0) {
            return Collections.EMPTY_LIST;
        }
        List<T> resList = new ArrayList<>();
        for (T t : dataList) {
            if (predicate.test(t)) {
                resList.add(t);
            }
        }
        return resList;
    }

    /**
     * 过滤出所有的属性
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> List<T> extract(Collection<E> dataList, Function<E, T> func) {
        if (dataList == null || dataList.size() == 0) {
            return new ArrayList<>();
        }
        List<T> resList = new ArrayList<>();
        T t;
        for (E e : dataList) {
            t = func.apply(e);
            if (t != null) {
                resList.add(t);
            }
        }
        return resList;
    }

    /**
     * 过滤出所有的属性
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> List<T> extractList(Collection<E> dataList, Function<E, Collection<T>> func) {
        if (dataList == null || dataList.size() == 0) {
            return new ArrayList<>();
        }
        List<T> resList = new ArrayList<>();
        Collection<T> ts;
        for (E e : dataList) {
            ts = func.apply(e);
            if (ts != null && ts.size() > 0) {
                resList.addAll(ts);
            }
        }
        return resList;
    }

    /**
     * 过滤出所有的属性
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> Set<T> extractToSet(Collection<E> dataList, Function<E, T> func) {
        if (dataList == null || dataList.size() == 0) {
            return new HashSet<>();
        }
        Set<T> resList = new HashSet<>();
        T t;
        for (E e : dataList) {
            t = func.apply(e);
            if (t != null) {
                resList.add(t);
            }
        }
        return resList;
    }

    /**
     * 过滤出所有的属性
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> List<T> extractSetList(Collection<E> dataList, Function<E, T> func) {
        if (dataList == null || dataList.size() == 0) {
            return new ArrayList<>();
        }
        List<T> resList = new ArrayList<>();
        T t;
        for (E e : dataList) {
            t = func.apply(e);
            if (t != null && !resList.contains(t)) {
                resList.add(t);
            }
        }
        return resList;
    }

    /**
     * 过滤出所有的属性
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> Set<T> extractListToSet(Collection<E> dataList, Function<E, Collection<T>> func) {
        if (dataList == null || dataList.size() == 0) {
            return new HashSet<>();
        }
        Set<T> resList = new HashSet<>();
        Collection<T> ts;
        for (E e : dataList) {
            ts = func.apply(e);
            if (ts != null && ts.size() > 0) {
                resList.addAll(ts);
            }
        }
        return resList;
    }


    /**
     * 转Map
     *
     * @param dataList
     * @param keyFunc
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> Map<T, E> map(Collection<E> dataList, Function<E, T> keyFunc) {
        return mapAction(dataList, keyFunc, v -> v);
    }

    /**
     * 转Map
     *
     * @param dataList
     * @param keyFunc
     * @return
     */
    public static <T, E, R> Map<T, R> map(Collection<E> dataList, Function<E, T> keyFunc, Function<E, R> valueFunc) {
        if (valueFunc == null) {
            return mapAction(dataList, keyFunc, v -> (R) v);
        }
        return mapAction(dataList, keyFunc, valueFunc);

    }

    /**
     * 转Map
     *
     * @param dataList
     * @param keyFunc
     * @return
     */
    private static <T, E, R> Map<T, R> mapAction(Collection<E> dataList, Function<E, T> keyFunc, Function<E, R> valueFunc) {
        if (dataList == null || dataList.size() == 0) {
            return Collections.EMPTY_MAP;
        }

        Map<T, R> resMap = new HashMap<>();
        T t;
        R r;
        for (E e : dataList) {
            t = keyFunc.apply(e);
            r = valueFunc.apply(e);
            if (t != null && r != null) {
                resMap.put(t, r);
            }
        }
        return resMap;
    }


    /**
     * 转MapList
     *
     * @param dataList
     * @param func
     * @param <T>
     * @param <E>
     * @return
     */
    public static <T, E> Map<T, List<E>> mapList(Collection<E> dataList, Function<E, T> func) {
        if (dataList == null || dataList.size() == 0) {
            return Collections.EMPTY_MAP;
        }
        Map<T, List<E>> resMap = new HashMap<>();
        T t;
        List<E> itemList;
        for (E e : dataList) {
            t = func.apply(e);
            if (t != null) {
                itemList = resMap.get(t);
                if (itemList == null) {
                    itemList = new ArrayList<>();
                }
                itemList.add(e);
                resMap.put(t, itemList);
            }
        }
        return resMap;
    }

    /**
     * 多级分组Map
     * <p>
     * 例子：
     * Map<String, Map<Integer, List<Bean>>> group = FnKit.map(beans, Collectors.groupingBy(Bean::getCode, Collectors.groupingBy(Bean::getType)));
     */
    public static <T, A, R> R map(Collection<T> dataList, Collector<? super T, A, R> collector) {
        if (dataList == null) {
            return null;
        }
        return dataList.stream().collect(collector);
    }

    /**
     * 转MapList
     * 例子：
     * FnKit.sort(beans,Bean::getType,Bean::getName);
     *
     * @param dataList
     * @param funcList
     * @param <E>
     * @return
     */
    public static <E> List<E> sort(List<E> dataList, Function<E, ? extends Comparable>... funcList) {
        if (dataList == null || dataList.size() == 0) {
            return Collections.EMPTY_LIST;
        }
        Collections.sort(dataList, new Comparator<E>() {
            @Override
            public int compare(E o1, E o2) {
                int r;
                Comparable c1;
                Comparable c2;
                for (Function<E, ? extends Comparable> func : funcList) {
                    c1 = func.apply(o1);
                    c2 = func.apply(o2);
                    if (c1 == null && c2 == null) {
                        continue;
                    } else if (c1 == null && c2 != null) {
                        return -1;
                    } else if (c1 != null && c2 == null) {
                        return 1;
                    } else {
                        r = c1.compareTo(c2);
                        if (r != 0) {
                            return r;
                        }
                    }
                }
                return 0;
            }
        });
        return dataList;
    }


    /**
     * 连接到一块
     *
     * @param dataList
     * @param <E>
     * @return
     */
    public static <E> String join(Collection<E> dataList) {
        if (dataList == null || dataList.size() == 0) {
            return "";
        }
        StringBuilder res = new StringBuilder();
        boolean init = false;
        for (E e : dataList) {
            if (init) {
                res.append(",");
            } else {
                init = true;
            }
            if (e instanceof String) {
                res.append((String) e);
            } else {
                res.append(e);
            }
        }
        return res.toString();
    }
    /**
     * 连接到一块
     *
     * @param dataList
     * @param <E>
     * @return
     */
    public static <E> String join(Collection<E> dataList,String defaultChar) {
        if (dataList == null || dataList.size() == 0) {
            return "";
        }
        StringBuilder res = new StringBuilder();
        boolean init = false;
        for (E e : dataList) {
            if (init) {
                res.append(defaultChar);
            } else {
                init = true;
            }
            if (e instanceof String) {
                res.append((String) e);
            } else {
                res.append(e);
            }
        }
        return res.toString();
    }
    /**
     * 转换
     *
     * @param codes
     * @return
     */
    public static List<String> toString(String codes) {
        if (codes == null || codes.length() == 0) {
            return Collections.EMPTY_LIST;
        }
        List<String> codeList = new ArrayList<>();
        codeList.addAll(Arrays.asList(codes.split(",")));
        return codeList;
    }

    /**
     * 转
     *
     * @param values
     * @return
     */
    public static List<Long> toLong(String values) {
        if (values == null || values.length() == 0) {
            return Collections.EMPTY_LIST;
        }
        String[] vArr = values.split(",");
        List<Long> resList = new ArrayList<>();
        for (String e : vArr) {
            try {
                resList.add(Long.valueOf(e));
            } catch (Exception ex) {
            }
        }
        return resList;
    }

    /**
     * 转
     *
     * @param value
     * @return
     */
    public static BigDecimal toBigDecimal(Object value) {
        if (value == null) {
            return BigDecimal.ZERO;
        }
        String v = value.toString().trim();
        if (v.length() == 0) {
            return BigDecimal.ZERO;
        }

        return BigDecimal.valueOf(Double.valueOf(v));
    }

    /**
     * 转
     *
     * @param dbList
     * @return
     */
    public static List<Long> toLong(Collection<String> dbList) {
        if (dbList == null || dbList.size() == 0) {
            return Collections.EMPTY_LIST;
        }
        List<Long> resList = new ArrayList<>();
        for (String e : dbList) {
            try {
                resList.add(Long.valueOf(e));
            } catch (Exception ex) {

            }

        }
        return resList;
    }


    /**
     * 判空，主要是为了简单记忆，这里做了个代理
     */
    public static boolean isEmpty(Object value) {
        if (value == null) {
            return true;
        }
        return ObjectUtil.isEmpty(value);
    }


    /**
     * 补充0，固定长度
     *
     * @param data
     * @param length
     * @return
     */
    public static String format(Object data, Integer length) {
        return String.format("%0" + length + "d", data);
    }


    /**
     * 锚点对齐
     *
     * @param anchor  对齐锚点
     * @param logList
     * @return
     */
    public static List<String> anchorAlign(Collection<String> logList, String anchor) {

        if (logList == null) {
            return Collections.EMPTY_LIST;
        }
        //建立一个空白字符串
        StringBuilder blank = new StringBuilder();
        String anchorReplace = "     ";
        for (int i = 0; i < 50; i++) {
            blank.append(anchorReplace);
        }
        //取得对齐位置
        int idx;
        int maxPosition = 0;
        for (String log : logList) {
            idx = log.indexOf(anchor);
            if (idx > maxPosition) {
                maxPosition = log.length();
            }
        }
        //锚点对齐
        List<String> resList = new ArrayList<>(logList.size());
        String tempLog;
        for (String log : logList) {
            tempLog = log.trim();
            idx = tempLog.indexOf(anchor);
            if (idx >= 0) {
                StringBuilder ss = new StringBuilder();
                ss.append(tempLog.substring(0, idx)).append(blank.substring(0, maxPosition - idx)).append(tempLog.substring(idx));
                resList.add(ss.toString());
            } else {
                resList.add(tempLog);
            }
        }
        return resList;
    }

    //开始字符
    private static String START_STR_SIGN = "#{";
    //结束字符
    private static String END_STR_SIGN = "}";


    /**
     * 分割属性列表
     *
     * @param txt
     * @param inCtx
     * @return
     * @throws Exception
     */
    public static String render(String txt, Map<String, Object> inCtx) {
        //分割成各个端
        List<String> segregateList = split(txt);
        //替换变量
        Map<String, Object> tempCtx = inCtx;
        if (tempCtx == null) {
            tempCtx = new HashMap<>();
        }
        StringBuilder res = new StringBuilder();
        String para;
        Object value;
        for (String segregate : segregateList) {
            if (segregate.startsWith(START_STR_SIGN)) {
                try {
                    para = segregate.substring(START_STR_SIGN.length(), segregate.length() - END_STR_SIGN.length());
                    if (para != null) {
                        para = para.trim();
                    }
                    value = tempCtx.get(para);
                    if (value == null) {
                        res.append(segregate);
                    } else {
                        res.append(value);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                    res.append(segregate);
                }
            } else {
                res.append(segregate);
            }
        }
        return res.toString();
    }




    /**
     * 参考org.springframework.jdbc.datasource.init.ScriptUtils#splitSqlScript
     *
     * @param script
     * @
     */
    public static List<String> split(String script) {
        //卫语句
        if (script == null || script.length() == 0) {
            return new ArrayList<>();
        }
        List<String> statements = new ArrayList<>();
        StringBuilder sb = new StringBuilder();
        boolean inPara = false;
        for (int i = 0; i < script.length(); i++) {
            char c = script.charAt(i);
            if (script.startsWith(START_STR_SIGN, i)) {
                if (sb.length() > 0) {
                    statements.add(sb.toString());
                    sb = new StringBuilder();
                }
                sb.append(c);
                inPara = true;
                continue;
            } else if (inPara && script.startsWith(END_STR_SIGN, i)) {
                sb.append(c);
                if (sb.length() > 0) {
                    statements.add(sb.toString());
                    sb = new StringBuilder();
                }
                inPara = false;
                continue;
            }
            //换行符 双引号中间的换行符，就直接跳过
            sb.append(c);
        }

        if (sb.length() > 0) {
            statements.add(sb.toString());
        }
        return statements;
    }


    /**
     * 分组
     *
     * @
     */
    public static <E> List<List<E>> split(Collection<E> dataList, int size) {
        //卫语句
        if (dataList == null || dataList.size() == 0) {
            return Collections.EMPTY_LIST;
        }
        int len = size;
        if (len <= 0) {
            len = 0;
        }
        List<List<E>> resList = new ArrayList<>();
        List<E> tempList = new ArrayList<>();
        for (E data : dataList) {
            tempList.add(data);
            if (tempList.size() == len) {
                resList.add(tempList);
                tempList = new ArrayList<>();
            }
        }
        if (tempList.size() > 0) {
            resList.add(tempList);
        }
        return resList;
    }

    /**
     * 分组
     *
     * @
     */
    public static <E> List<List<E>> splitToGroup(List<E> dataList, int size) {
        Map<Integer, List<E>> idxMap = new HashMap();
        List<E> idxList;
        int idx;
        for (int j = 0; j < dataList.size(); j++) {
            idx = j % size;
            idxList = idxMap.get(j % size);
            if (idxList == null) {
                idxList = new ArrayList<>();
                idxMap.put(idx, idxList);
            }
            idxList.add(dataList.get(j));
        }
        List<List<E>> resList = new ArrayList<>();
        resList.addAll(idxMap.values());
        return resList;
    }

    /**
     * 两个Map是否相等
     *
     * @param srcData
     * @param tarData
     * @return
     */
    public static boolean equals(Map<String, Object> srcData, Map<String, Object> tarData) {
        if (srcData == null || tarData == null) {
            return false;
        }
        if (srcData.size() != tarData.size()) {
            return false;
        }
        Object srcValue;
        Object tarValue;
        for (Map.Entry<String, Object> entry : tarData.entrySet()) {
            srcValue = entry.getValue();
            if (srcValue == null) {
                return false;
            }
            tarValue = entry.getValue();
            //不相等
            if (!srcValue.equals(tarValue)) {
                return false;
            }
        }
        return true;
    }
}
